#!coding:utf-8
import netaddr
from rest_framework import status
from cvirt.common import utils
from cvirt.manager.serializers import NetworkSerializer, FixedipSerializer
from cvirt.manager.views import BaseListAPIView,BaseRetriveAPIView,NamedAPIViewMixIn
from cvirt.manager.models import Network, Cluster, FixedIp, Server
from django.forms.models import model_to_dict
from cvirt.common import constant,translate as _
from rest_framework.response import Response
from cvirt import tasks
from django.db.models import Q
from django.db import transaction

class Networks(NamedAPIViewMixIn,BaseListAPIView):
    serializer_class = NetworkSerializer
    model = Network

    def _get(self,request,*args,**kwargs):
        qset = self.model.objects.all()
        data = self.paginate(request,qset,self.serializer_class)
        return Response(data)

    def random_mac(self,reqeust,*args,**kwargs):
        return Response(dict(mac=utils.generate_mac()))

    def validate_ip(self,ip):
        try:
            return netaddr.IPAddress(ip)
        except:
            pass

    @transaction.commit_on_success
    def create(self,request,*args,**kwargs):
        """

        @param request:
        @param args:
        @param kwargs:
        @return:
        """
        network = self.get_params("network")
        networktype = int(network['networktype'])
        name = network['name']
        rundhcp = network['rundhcp'] if network.has_key('rundhcp') else False
        netmask = network['netmask'] if rundhcp else None

        dhcp_start = network['dhcp_start'] if rundhcp else None
        dhcp_end = network['dhcp_end'] if rundhcp else None

        cluster_id = network['cluster']['id']
        cidr = None
        address = None
        cluster = Cluster.objects.get_or_none(pk=network['cluster']['id'])

        if cluster:
            if not tasks.createNat.alive_hosts(cluster.id):
                return Response(_("集群中没有活动的主机"),status.HTTP_400_BAD_REQUEST)

            #首先name不能重复
            networkobj = Network.objects.get_or_none(name=name,cluster_id=cluster_id)
            if networkobj:
                return Response(_('网络%s已存在') % name,status.HTTP_400_BAD_REQUEST)

            if rundhcp:
                start = self.validate_ip(dhcp_start)
                end = self.validate_ip(dhcp_end)
                #检查ip是否合法
                if not start or not end:
                    return Response(_('dhcp开始或结束不是合法的ip地址'),status.HTTP_400_BAD_REQUEST)
                netmaskobj = self.validate_ip(netmask)
                #检查是否合法的netmask
                if not netmaskobj or not netmaskobj.is_netmask():
                    return Response(_('掩码地址不合法'),status.HTTP_400_BAD_REQUEST)

                ipnetwork = netaddr.IPNetwork('%s/%s' % (dhcp_start,netmask))
                #检查是否在掩码范围内
                if start not in ipnetwork or end not in ipnetwork:
                    return Response(_('dhcp开始或结束不在同一个网段'),status.HTTP_400_BAD_REQUEST)

                cidr = str(ipnetwork.cidr)
                address = str(ipnetwork[1])
                #如果名字不重复，则检查cidr，但是cidr不能为空
                if cidr:
                    if Network.objects.get_or_none(cidr=cidr,cluster_id=cluster_id):
                        return Response(_('网段%s已存在' % cidr),status.HTTP_400_BAD_REQUEST)

                ipnumbers = len(netaddr.IPRange(start,end))
                hostnumber = Server.objects.filter(cluster=cluster).count()
                if ipnumbers < hostnumber:
                    return Response(_('输入的ip地址数量必须大于集群中主机数量(%s)' % hostnumber),status.HTTP_400_BAD_REQUEST)

            attrs = dict(name=name,cidr=cidr,rundhcp=rundhcp,dhcp_start=dhcp_start,dhcp_end=dhcp_end,
                         cluster=cluster,networktype=networktype,netmask=netmask,cast_snoop=network['cast_snoop'])

            if networktype == constant.NAT or networktype == constant.ISOLATE:
                net = Network.objects.create(address=address,**attrs)
                if networktype == constant.NAT:
                    result = tasks.createNat.cluster_call(cluster_id,net)
                if networktype == constant.ISOLATE:
                    result = tasks.createIsolate.cluster_call(cluster_id,net)
            else:
                gateway = network['gateway'] if rundhcp and network.has_key('gateway') else None
                dns1 = network['dns1'] if rundhcp and network.has_key('dns1') else None
                dns2 = network['dns2'] if rundhcp and network.has_key('dns2') else None
                if rundhcp:
                    gatewayobj = self.validate_ip(gateway)
                    if not gatewayobj or not gatewayobj in ipnetwork:
                        return Response(_('网关不是一个合法的ip地址'),status.HTTP_400_BAD_REQUEST)

                if networktype == constant.BRIDGE:
                    if Network.objects.get_or_none(networktype=constant.BRIDGE,cluster=cluster):
                        return Response(_('集群中只允许存在一个桥接网络'),status.HTTP_400_BAD_REQUEST)

                    net = Network.objects.create(gateway=gateway,dns1=dns1,dns2=dns2,**attrs)
                    net.update(dict(bridge="br_%s" % net.libvirt_name))  #由于数据库使用软删除，这里要保证网桥名字的唯一性
                    result = tasks.createBridge.cluster_call(cluster_id,net)

                if networktype == constant.VLAN:
                    vlanid = network['vlanid']
                    if Network.objects.get_or_none(vlanid=vlanid,cluster_id=cluster_id):
                        return Response(_("vlan id已经存在"),status.HTTP_400_BAD_REQUEST)

                    net = Network.objects.create(bridge="br-%s" % name,gateway=gateway,dns1=dns1,dns2=dns2,
                                                vlanid=vlanid,**attrs)
                    result = tasks.createVlan.cluster_call(cluster_id,net)
            data = self.get_serializer(net).data
            data.update(dict(activity=result.id))
            return Response(data,200)
        else:
            return Response("cluster id can not be null",400)


class NetworkDetail(NamedAPIViewMixIn,BaseRetriveAPIView):
    serializer_class = NetworkSerializer
    model = Network
    def validate_ip(self,ip):
        try:
            return netaddr.IPAddress(ip)
        except:
            pass

    def fixedips(self,request,*args,**kwargs):
        include = self.get_query_string('include')
        if include:
            ips = FixedIp.objects.filter(Q(allocated=False)|Q(id=include),network_id=self.pk)
        else:
            ips = FixedIp.objects.filter(network_id=self.pk,allocated=False)
        return Response(FixedipSerializer(ips,many=True).data)


    def delete(self,request,*args,**kwargs):
        network = Network.objects.get_or_none(pk=self.pk)
        if network:
            if network.interface_set.count() != 0:
                return Response(_("网络有关联的虚拟机，不允许删除"),status.HTTP_400_BAD_REQUEST)

            activity = tasks.delete_network.cluster_call(network.cluster.id,network)
            return Response(dict(activity=activity.id))
        else:
            return Response('network can not be null',status.HTTP_400_BAD_REQUEST)


    def update(self, request, *args, **kwargs):
        """

        @param request:
        @param args:
        @param kwargs:
        @return:
        """
        network = self.get_params("network")
        networktype = int(network['networktype'])
        rundhcp = network['rundhcp'] if network.has_key('rundhcp') else False
        netmask = network['netmask'] if rundhcp else None

        dhcp_start = network['dhcp_start'] if rundhcp else None
        dhcp_end = network['dhcp_end'] if rundhcp else None

        cluster_id = network['cluster']['id']
        cidr = None
        address = None
        cluster = Cluster.objects.get_or_none(pk=network['cluster']['id'])
        net = Network.objects.get_or_none(pk=self.pk)
        if cluster and net:
            last_cidr = net.cidr
            if not tasks.createNat.alive_hosts(cluster.id):
                return Response(_("集群中没有活动的主机"),status.HTTP_400_BAD_REQUEST)
            if rundhcp:
                start = self.validate_ip(dhcp_start)
                end = self.validate_ip(dhcp_end)
                #检查ip是否合法
                if not start or not end:
                    return Response(_('dhcp开始或结束不是合法的ip地址'),status.HTTP_400_BAD_REQUEST)
                netmaskobj = self.validate_ip(netmask)
                #检查是否合法的netmask
                if not netmaskobj or not netmaskobj.is_netmask():
                    return Response(_('掩码地址不合法'),status.HTTP_400_BAD_REQUEST)

                ipnetwork = netaddr.IPNetwork('%s/%s' % (dhcp_start,netmask))
                #检查是否在掩码范围内
                if start not in ipnetwork or end not in ipnetwork:
                    return Response(_('dhcp开始或结束不在同一个网段'),status.HTTP_400_BAD_REQUEST)

                cidr = str(ipnetwork.cidr)
                address = str(ipnetwork[1])

            attrs = dict(cidr=cidr,rundhcp=rundhcp,dhcp_start=dhcp_start,dhcp_end=dhcp_end,netmask=netmask,
                         cast_snoop=network['cast_snoop'])

            if networktype == constant.NAT or networktype == constant.ISOLATE:
                net.update(dict(address=address,**attrs))
                if networktype == constant.NAT:
                    result = tasks.updateNat.cluster_call(cluster_id,net) #修改和新建执行一样的操作
                if networktype == constant.ISOLATE:
                    result = tasks.updateIsolate.cluster_call(cluster_id,net)#修改和新建执行一样的操作

            else:
                gateway = network['gateway'] if rundhcp and network.has_key('gateway') else None
                dns1 = network['dns1'] if rundhcp and network.has_key('dns1') else None
                dns2 = network['dns2'] if rundhcp and network.has_key('dns2') else None
                if rundhcp:
                    gatewayobj = self.validate_ip(gateway)
                    if not gatewayobj or not gatewayobj in ipnetwork:
                        return Response(_('网关不是一个合法的ip地址'),status.HTTP_400_BAD_REQUEST)

                if networktype == constant.BRIDGE:

                    net.update(dict(gateway=gateway,dns1=dns1,dns2=dns2,bridge="br_%s" % net.libvirt_name,**attrs))#由于数据库使用软删除，这里要保证网桥名字的唯一性
                    result = tasks.updateBridge.cluster_call(cluster_id,net,last_cidr=last_cidr)

                if networktype == constant.VLAN:
                    vlanid = network['vlanid']
                    net.update(dict(bridge="br-%s" % net.libvirt_name,gateway=gateway,dns1=dns1,dns2=dns2,
                                                vlanid=vlanid,**attrs))
                    result = tasks.updateVlan.cluster_call(cluster_id,net,last_cidr=last_cidr)
            data = self.get_serializer(net).data
            data.update(dict(activity=result.id))
            return Response(data,200)
        else:
            return Response("cluster id can not be null",400)
